home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 April: Mac OS SDK / Dev.CD Apr 00 SDK1.toast / Development Kits / Mac OS / Thread Manager / Sample Applications / 68k Examples / Dining Philos (THINK⁄MPW) / PhiloMain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-17  |  13.0 KB  |  569 lines  |  [TEXT/MPS ]

  1. #ifndef THINK_C
  2. #include <Memory.h>
  3. #include <Windows.h>
  4. #include <Menus.h>
  5. #include <QuickDraw.h>
  6. #include <Fonts.h>
  7. #include <TextEdit.h>
  8. #include <OSEvents.h>
  9. #include <Dialogs.h>
  10. #include <Packages.h>
  11. #include <ToolUtils.h>
  12. #include <Desk.h>
  13. #include <ThreadUtil.h>
  14. #include <GestaltEqu.h>
  15. #include <Types.h>
  16. #include <QDOffscreen.h>
  17. #endif
  18.  
  19. #include "ProtoStructs.h"
  20.  
  21. /***********************************************************************************
  22. **
  23. ** Almighty global declarations
  24. **
  25. */
  26. short                 gDone, gInBackground;
  27. philoRecord            gPhilosophizer[kNumOfPhilosophizers];
  28. CIconHandle         gNoForkIcon, gLeftForkIcon, gBothForksIcon;
  29. SimpleSemaphorePtr    gForks[kNumOfPhilosophizers];
  30. GWorldPtr            gOffscreenWorld;
  31.  
  32.  
  33. /***********************************************************************************
  34. **
  35. ** Make sure that this machine has ColorQD and the Thread Mgr.
  36. */
  37. void system_attrib()
  38. {
  39.     long    res;
  40.     short    comparebit;
  41.     OSErr    returnErr;
  42.     
  43.     returnErr = Gestalt (gestaltQuickdrawVersion, &res);
  44.     
  45.     if ( returnErr != noErr )
  46.         error("\pProblem with Gestalt in system_attrib", returnErr, kFatal);
  47.  
  48.     comparebit = gestaltOriginalQD;
  49.     
  50.     if (BitTst(&res, 31 - comparebit) == TRUE)
  51.         error("\pSorry, you need Color QuickDraw to run.", returnErr, kFatal);
  52.  
  53.     returnErr = Gestalt (gestaltThreadMgrAttr, &res);
  54.     
  55.     if ( returnErr != noErr )
  56.         if ( returnErr == gestaltUndefSelectorErr )
  57.             error("\pSorry, you gotta have >>THREADS<< (The Thread Manager)",
  58.                     returnErr, 
  59.                     kFatal);
  60.         else
  61.             error("\pProblem with Gestalt in sys_attrib", returnErr, kFatal);
  62.  
  63.     comparebit = gestaltThreadMgrPresent;
  64.     
  65.     if (BitTst(&res, 31 - comparebit) == FALSE) /* If Thread Mgr isn't loaded */
  66.         error("\pSorry, you gotta have >>THREADS<< (The Thread Manager)", 
  67.                     returnErr, 
  68.                     kFatal);
  69.  
  70. }    
  71.  
  72.  
  73. /***********************************************************************************
  74. **
  75. ** I put the MaxAppleZone() call out here, to make sure 
  76. ** that it is called first.
  77. */
  78. void main()
  79. {
  80.     WindowPtr    appWindow;
  81.     MaxApplZone();
  82.     
  83.     init_mac();
  84.     InitializeThreadUtilities();
  85.     init_threads();
  86.     
  87.     appWindow = init_rooms();
  88.     init_philosophizers(appWindow);
  89.     spawn_threads();
  90.     event_loop();
  91. }
  92.  
  93.  
  94. /***********************************************************************************
  95. **
  96. ** A general purpose error display routine that works with two ALRT resources.
  97. */
  98. void error(Str255 err_string, short err_val, short fatal)
  99. {
  100.     Str255 num_string = "\p";
  101.     
  102.     NumToString((long)err_val, num_string);
  103.     ParamText(err_string, num_string, 0, 0);
  104.  
  105.     if ( fatal )
  106.     {
  107.         (void)Alert(kErrorAlert, nil);
  108.              ExitToShell();
  109.     }
  110.     else
  111.         (void)Alert(kErrorAlert, nil);    
  112. }
  113.  
  114.  
  115. /***********************************************************************************
  116. **
  117. ** It's a DA window if the windowKind field is less than 0
  118. */
  119. short is_DA_window(WindowPtr win)
  120. {
  121.     if ( (win == nil) || ((*(WindowPeek)win).windowKind >= 0) )
  122.         return(FALSE);
  123.     else
  124.         return(TRUE);
  125. }
  126.  
  127.  
  128. /***********************************************************************************
  129. **
  130. ** Standard Macintosh application initialization.
  131. */
  132. void init_mac()
  133. {
  134.  
  135. #ifndef THINK_C
  136.     InitGraf(&qd.thePort);
  137. #else
  138.     InitGraf(&thePort);
  139. #endif
  140.     InitFonts();
  141.     InitWindows();
  142.     InitMenus();
  143.     InitCursor();
  144.     TEInit();            // To make sure that DAs, dialogs and alerts work OK
  145.     FlushEvents(everyEvent, 0);
  146.     InitDialogs(0L);    
  147.     system_attrib();    // Check up on this Mac's attributes.
  148.     SetMenuBar(GetNewMBar(128));
  149.     AddResMenu(GetMHandle(kAppleMenu), 'DRVR');
  150.     DrawMenuBar();
  151.     
  152.     gDone = FALSE;
  153.     gInBackground = FALSE;
  154.     
  155.     gNoForkIcon = GetCIcon(kNoForkIcon);
  156.     gLeftForkIcon = GetCIcon(kLeftForkIcon);
  157.     gBothForksIcon = GetCIcon(kBothForksIcon);
  158. }
  159.  
  160.  
  161. /***********************************************************************************
  162. **
  163. ** Set up each philosopizer's icon locations and initial state.
  164. */
  165. void init_philosophizers(WindowPtr win)
  166. {
  167.     short    index;
  168.     
  169.     for ( index = 0; index < kNumOfPhilosophizers; index++ )
  170.     {
  171.     /* Thinking locations */        
  172.         gPhilosophizer[index].thinking_location.top = 
  173.                         win->portRect.top + kIconOffset + (kIconDimension * index) + 
  174.                         (kIconOffset * index);
  175.         gPhilosophizer[index].thinking_location.bottom = 
  176.                         gPhilosophizer[index].thinking_location.top + kIconDimension;
  177.         gPhilosophizer[index].thinking_location.left = 
  178.                         win->portRect.right - (kIconOffset + kIconDimension);
  179.         gPhilosophizer[index].thinking_location.right = 
  180.                         gPhilosophizer[index].thinking_location.left + kIconDimension;
  181.  
  182.     /* Waiting locations */        
  183.         gPhilosophizer[index].waiting_location.top = gPhilosophizer[index].thinking_location.top;
  184.         gPhilosophizer[index].waiting_location.bottom = gPhilosophizer[index].waiting_location.top + kIconDimension;
  185.         gPhilosophizer[index].waiting_location.left = gPhilosophizer[index].thinking_location.left - 150;
  186.         gPhilosophizer[index].waiting_location.right = gPhilosophizer[index].waiting_location.left + kIconDimension;
  187.  
  188.  
  189.     /* Dining locations */        
  190.         gPhilosophizer[index].dining_location.top = 
  191.                         win->portRect.top + kIconOffset + (kIconDimension * index) + 
  192.                         (kIconOffset * index);
  193.         gPhilosophizer[index].dining_location.bottom = 
  194.                         gPhilosophizer[index].thinking_location.top + kIconDimension;
  195.         gPhilosophizer[index].dining_location.left = 
  196.                         win->portRect.left + kIconOffset;
  197.         gPhilosophizer[index].dining_location.right = 
  198.                         gPhilosophizer[index].dining_location.left + kIconDimension;
  199.  
  200.         gPhilosophizer[index].left_fork = index;
  201.  
  202.     /* Philo's initial attributes */
  203.         gPhilosophizer[index].fork_state = kNoForks;
  204.         gPhilosophizer[index].current_location = gPhilosophizer[index].thinking_location;
  205.     }
  206. }
  207.  
  208.  
  209. /***********************************************************************************
  210. **
  211. ** You can create Preemptive threads right here, just make sure to change what's
  212. ** in spawn_threads, too.
  213. */
  214. void init_threads()
  215. {
  216.     OSErr    anError;
  217.     
  218.     /* Make a pool of threads for the Philos */
  219.     anError = CreateThreadPool(kCooperativeThread, kNumOfPhilosophizers, (Size)0);
  220.     if ( anError )
  221.         error ("\pProblem creating thread pool", anError, kFatal);
  222.         
  223.     /* Make a Footman (to prevent deadlock) */
  224.     create_footman();
  225.  
  226.     /* Make the forks (an array of SimpleSemaphores) */
  227.     create_forks();
  228. }
  229.  
  230.  
  231. /***********************************************************************************
  232. **
  233. ** Set up the offscreen GWorld, for those fast updates
  234. */
  235. WindowPtr init_rooms()
  236. {
  237.     QDErr     anError;
  238.     WindowPtr     new_window;
  239.     Rect        win_rect = {50, 50, 300, 500};
  240.         
  241.     /*
  242.     ** First draw the new window
  243.     */        
  244.     new_window = NewCWindow(nil, &win_rect, 
  245.                             "\pDining Philosophizers", FALSE, 
  246.                             noGrowDocProc, (WindowPtr)-1, 
  247.                             TRUE, 0L);
  248.     ShowWindow(new_window);
  249.  
  250.     anError = NewGWorld(&gOffscreenWorld, 
  251.                     0, 
  252.                     &new_window->portRect, 
  253.                     nil, 
  254.                     nil, 
  255.                     keepLocal);
  256.  
  257.     if (anError)
  258.         error("\pCouldn't create the GWorld", anError, kFatal);
  259.         
  260.     return new_window;
  261. }
  262.  
  263.  
  264. /***********************************************************************************
  265. **
  266. ** Takes the result from a menu call (either from keys or the mouse) and figures out
  267. ** where to go.
  268. */
  269. void menu_command(long result)
  270. {
  271.     short    menu_ID, item_num;
  272.     
  273.     menu_ID = HiWord(result);
  274.     item_num = LoWord(result);
  275.  
  276.     switch( menu_ID )
  277.     {
  278.         case kAppleMenu:
  279.             HiliteMenu(kAppleMenu);
  280.             do_apple_menu(item_num);
  281.             break;
  282.         
  283.         case kFileMenu:
  284.             HiliteMenu(kFileMenu);
  285.             switch( item_num )
  286.             {
  287.                 case kQuitItem: gDone = TRUE;    break;        
  288.             }
  289.             break;
  290.     }
  291.     HiliteMenu(0);    
  292. }
  293.  
  294.  
  295. /***********************************************************************************
  296. **
  297. ** Called by menu_command().
  298. */
  299. void do_apple_menu(short item)
  300. {
  301.     Str255    da_name;
  302.     GrafPtr    orig_port;
  303.     
  304.     if ( item == kAboutItem )
  305.         (void)Alert(kAboutThisApp,nil);
  306.     else
  307.     {    
  308.         GetItem(GetMHandle(kAppleMenu), item, da_name);
  309.         GetPort(&orig_port);
  310.         OpenDeskAcc(da_name);
  311.         SetPort(orig_port);
  312.     }
  313. }
  314.  
  315.  
  316. /***********************************************************************************
  317. **
  318. ** The Philosophizers are updated at every null event
  319. */
  320. void event_loop()
  321. {
  322.     EventRecord    my_evt;
  323.     short        got_evt = 0;
  324.     OSErr        anError;
  325.     WindowPtr    win;
  326.     
  327.     while( !gDone )
  328.     {
  329.         ThreadBeginCritical();
  330.         
  331.         got_evt = WaitNextEvent(everyEvent, &my_evt, kSleepTicks, nil);
  332.         
  333.         if ( got_evt )
  334.         {
  335.             switch( my_evt.what )
  336.             {
  337.                 case nullEvent:                            break;
  338.                 case mouseDown:    mousedown_evt(my_evt);    break;    
  339.                 case mouseUp:                            break;
  340.                 case keyDown:    keydown_evt(my_evt);    break;
  341.                 case keyUp:                                break;
  342.                 case autoKey:                            break;
  343.                 case updateEvt:    update_evt(my_evt);        break;
  344.                 case diskEvt:                            break;
  345.                 case activateEvt:                        break;
  346.                 case networkEvt:                        break;
  347.                 case driverEvt:                            break;
  348.                 case app1Evt:                            break;                
  349.                 case app2Evt:                            break;
  350.                 case app3Evt:                            break;
  351.                 case app4Evt: suspend_resume_evt(my_evt);    break;
  352.                 default :                         break;
  353.             }
  354.         }
  355.         else
  356.         {
  357.             win = FrontWindow();
  358.             if ( !is_DA_window(win) && (!gInBackground) )
  359.                 draw_and_slam(win);
  360.         }
  361.         
  362.         ThreadEndCritical();
  363.         
  364.         anError = YieldToAnyThread();
  365.         if ( anError )
  366.             error ("\pError in yielding the main thread", anError, kFatal);
  367.     }
  368.     /* Shutdown routines */
  369.     remove_forks();
  370.     retire_footman();
  371. }
  372.  
  373.  
  374. /***********************************************************************************
  375. **
  376. ** Sets the background global, and draws the grow icon.
  377. */
  378. void suspend_resume_evt(EventRecord event)
  379. {
  380.     if ( event.message & 0x01000000 )         /* Is it a suspend or resume? */
  381.     {
  382.         if ( event.message & 0x00000001 )    /* Is it a resume event? */
  383.             gInBackground = FALSE;
  384.         else                                /* It's a suspend event */
  385.             gInBackground = TRUE;
  386.  
  387.     }
  388. }
  389.  
  390.  
  391. /***********************************************************************************
  392. **
  393. ** Handle keyboard events by eventually calling menu_command.
  394. */
  395. void keydown_evt(EventRecord event)
  396. {
  397.     char    key;
  398.     long    result;
  399.  
  400.     key = event.message & charCodeMask;
  401.             
  402.     if ( (event.modifiers & cmdKey) != 0 ) 
  403.     {
  404.         result = MenuKey(key);
  405.         if ( HiWord(result) != 0 )    /* Is it a valid key? */
  406.             menu_command(result);                
  407.     }
  408.     else
  409.         SysBeep(3);        /* It's a normal keystroke, just beep */
  410.         
  411. }
  412.  
  413.  
  414. /***********************************************************************************
  415. **
  416. ** Handle mouse down events
  417. */
  418. void mousedown_evt(EventRecord event)
  419. {
  420.     WindowPtr    win;
  421.     long        result;
  422.     Point        mouse_point;
  423.     GrafPtr        orig_port;
  424.     short        ret_val;
  425.     
  426.     ret_val = FindWindow(event.where, &win);
  427.     
  428.     switch ( ret_val )
  429.     {
  430.         case inDesk:         break;
  431.         case inMenuBar:
  432.             result = MenuSelect(event.where);
  433.             if ( HiWord(result) != 0 )
  434.                 menu_command(result);
  435.             break;
  436.  
  437.         case inSysWindow:     break;
  438.         
  439.         case inContent: 
  440.             GetPort(&orig_port);
  441.             SetPort(win);
  442.             
  443.             mouse_point = event.where;
  444.             GlobalToLocal(&mouse_point);
  445.     
  446.             if ( win != FrontWindow() )
  447.                 SelectWindow(win);
  448.                             
  449.             SetPort(orig_port);
  450.             break;
  451.             
  452.         case inDrag:
  453. #ifndef THINK_C
  454.             DragWindow(win, event.where, &qd.screenBits.bounds); 
  455. #else
  456.             DragWindow(win, event.where, &screenBits.bounds); 
  457. #endif
  458.             break;
  459.             
  460.         case inGrow: 
  461.             break;
  462.             
  463.         case inGoAway: 
  464.             if ( TrackGoAway(win, event.where) )
  465.                 gDone = TRUE;
  466.             break;
  467.  
  468.         case inZoomIn:         break;
  469.         case inZoomOut:        break;
  470.     }
  471. }
  472.  
  473.  
  474. /***********************************************************************************
  475. **
  476. ** Update the content rect of the window, set the clip rgn to this content rect, 
  477. ** draw the tools, and reset the clip rgn to normal.
  478. */
  479. void update_evt(EventRecord event)
  480. {
  481.     GrafPtr        orig_port;
  482.     WindowPtr    update_win;
  483.     
  484.     update_win = (WindowPtr)event.message;
  485.     GetPort(&orig_port);
  486.     SetPort(update_win);
  487.     
  488.  
  489.     BeginUpdate(update_win);
  490.         draw_and_slam(update_win);
  491.     EndUpdate(update_win);
  492.     
  493.     SetPort(orig_port);
  494. }
  495.  
  496.  
  497. /***********************************************************************************
  498. **
  499. ** Get PICT 128 and draw it to the current GrafPort
  500. */
  501. void draw_background(WindowPtr win)
  502. {
  503.     PicHandle ph = GetPicture(kPictID);
  504.     DrawPicture(ph, &win->portRect);    
  505. }
  506.  
  507.  
  508. /***********************************************************************************
  509. **
  510. ** Draw it according to its fork state (three different icons.
  511. */
  512. void draw_philosophizers(WindowPtr win)
  513. {
  514.     short    index;
  515.  
  516.     SetPort(win);
  517.     for ( index = 0; index < kNumOfPhilosophizers; index++ )
  518.     {
  519.         switch ( gPhilosophizer[index].fork_state )
  520.         {
  521.             case kNoForks :
  522.                 PlotCIcon(&(gPhilosophizer[index].current_location), gNoForkIcon);
  523.                 break;
  524.             
  525.             case kLeftFork :
  526.                 PlotCIcon(&(gPhilosophizer[index].current_location), gLeftForkIcon);
  527.                 break;
  528.                 
  529.             case kBothForks :
  530.                 PlotCIcon(&(gPhilosophizer[index].current_location), gBothForksIcon);
  531.                 break;
  532.         }
  533.     }
  534. }
  535.  
  536.  
  537. /***********************************************************************************
  538. **
  539. ** The name says it all
  540. */
  541. void draw_and_slam(WindowPtr win)
  542. {
  543.     GrafPtr    old_port;
  544.  
  545.     GetPort(&old_port);
  546.     SetPort((WindowPtr)gOffscreenWorld);
  547.     
  548.     LockPixels(gOffscreenWorld->portPixMap);
  549.     draw_background((WindowPtr)gOffscreenWorld);
  550.     draw_philosophizers((WindowPtr)gOffscreenWorld);
  551.     UnlockPixels(gOffscreenWorld->portPixMap);
  552.  
  553.     SetPort(win);
  554.     
  555.     HLock((Handle)(gOffscreenWorld->portPixMap));
  556.  
  557.     CopyBits((const BitMap *)*(gOffscreenWorld->portPixMap),
  558.                 (const BitMap *)&(win->portBits),
  559.                 &gOffscreenWorld->portRect,
  560.                 &(win->portRect),
  561.                 srcCopy,
  562.                 nil);
  563.     
  564.     HUnlock((Handle)(gOffscreenWorld->portPixMap));
  565.  
  566.     SetPort(old_port);
  567. }
  568.  
  569.